package nconv.convert;
import nconv.convert.generator.TGPPToCGenerator;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class TGPPRefProcessor {
	private static Map<String, String> map = null;
	private static Map<String, String> rmap = new HashMap<>();
	private static Map<String, List<String>> pageMap = new HashMap<>();
	
	public static final String PAGE_MARK_BEGIN = "<#";
	public static final String PAGE_MARK_END = "#>";
	
	public static final String NO_PAGE_MARK = "<>";
	
	public static final String SPEC_CLAUSE_CAT_MARK = "##";
	public static final String PAGE_DIV_CAT_MARK = "<*>";

	public static final String PARAGRAPH_SKIP_START = "<^skip>";
	public static final String PARAGRAPH_SKIP_END = "<skip$>";
	
	public static void reloadRefs(boolean forceReload) throws FileNotFoundException, IOException {
		if (map != null && !forceReload) {
			return;
		}
		
		if (map == null) {
			map = new HashMap<String, String>();
		} else {
			map.clear();
		}
		rmap.clear();
		
		try (BufferedReader br = new BufferedReader(new FileReader("input/toc.txt"))) {
			String line = null;
			String spec = null;
			String page = null;
			String backedPage = null;
			while ((line = br.readLine()) != null) {
				line = line.trim();
				if (line.startsWith(TGPPToCGenerator.SPEC_OPEN_MARK_BEGIN) && line.endsWith(TGPPToCGenerator.SPEC_OPEN_MARK_END)) {
					spec = line.substring(TGPPToCGenerator.SPEC_OPEN_MARK_BEGIN.length(), line.length() - TGPPToCGenerator.SPEC_OPEN_MARK_END.length());
					pageMap.put(spec, new ArrayList<>());
					page = null;
				} else if (line.startsWith(TGPPToCGenerator.SPEC_CLOSE_MARK_BEGIN) && line.endsWith(TGPPToCGenerator.SPEC_CLOSE_MARK_END)) {
					spec = null;
					page = null;
				} else if (line.startsWith(PAGE_MARK_BEGIN) && line.endsWith(PAGE_MARK_END)) {
					page = line.substring(PAGE_MARK_BEGIN.length(), line.length() - PAGE_MARK_END.length());
					if (spec != null && pageMap.containsKey(spec)) {
						pageMap.get(spec).add(page);
					}
				} else if (line.equals(NO_PAGE_MARK)) {
					page = null;
				} else if (line.equals(PARAGRAPH_SKIP_START)) {
					backedPage = page;
					page = null;
				} else if (line.equals(PARAGRAPH_SKIP_END)) {
					page = backedPage;
					backedPage = null;
				} else {
					if (spec != null && page != null) {
						String[] fields = line.split("\\t");
						if (fields.length < 2) {
							System.err.println("Bad line without tab: " + line);
						} else {
							boolean isClausePage = fields[0].startsWith(TGPPToCGenerator.PAGE_CLAUSE_MARK);
							String clause = spec + SPEC_CLAUSE_CAT_MARK
									+ (isClausePage ? fields[0].substring(TGPPToCGenerator.PAGE_CLAUSE_MARK.length()) : fields[0]);
							String refLoc = (isClausePage ? page : (page + PAGE_DIV_CAT_MARK + fields[1]));
							if (rmap.get(refLoc) != null) { // taken!
								refLoc = page + PAGE_DIV_CAT_MARK + fields[0] + "-" + fields[1];
							}

							map.put(clause, refLoc);
							rmap.put(refLoc, clause);
						}
					}
				}
			}
			
		}
	}

	public static List<String> getSpecPages(String specName) {
		return pageMap.get(specName);
	}
	
	public static String lookForRefLoc(String doc, String clause) {
		if (map == null) {
			try {
	      reloadRefs(true);
      } catch (IOException e) {
	      return null;
      }
		}
		doc = doc.replace(".", "");
		String clauseKey = doc + SPEC_CLAUSE_CAT_MARK + clause;
		return map.get(clauseKey);
	}
	
	public static String lookForDivId(String doc, String clause) {
		String refLoc = lookForRefLoc(doc, clause);
		if (refLoc == null) {
			return null;
		} else {
			int idx = refLoc.indexOf(PAGE_DIV_CAT_MARK);
			if (idx < 0) {
				return null;
			}
			return refLoc.substring(idx + PAGE_DIV_CAT_MARK.length());
		}		
	}
	
	public static String validateClause(String clause) {
		if (clause != null && clause.endsWith(".")) {
  		return clause.substring(0, clause.length() - 1);
		} 
		return clause;
	}
}
